package cn.trigram.mgb.api.java;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.ConnectionFactory;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.internal.ObjectFactory;


public class RemarkJDBCConnectionFactory implements ConnectionFactory {

  private String userId;

  private String password;

  private String connectionURL;

  private String driverClass;

  private String remarksReporting;

  private String useInformationSchema;

  private Properties otherProperties;

  /**
   * This constructor is called when there is a JDBCConnectionConfiguration specified in the configuration.
   *
   * @param config
   *     the configuration
   */
  public RemarkJDBCConnectionFactory(JDBCConnectionConfiguration config) {

    super();
    userId               = config.getUserId();
    password             = config.getPassword();
    connectionURL        = config.getConnectionURL();
    driverClass          = config.getDriverClass();
    remarksReporting     = StringUtils.defaultIfBlank(config.getProperty("remarksReporting"), "true");
    useInformationSchema = StringUtils.defaultIfBlank(config.getProperty("useInformationSchema"), "true");
    otherProperties      = config.getProperties();
  }

  /**
   * This constructor is called when this connection factory is specified as the type in a ConnectionFactory
   * configuration element.
   */
  public RemarkJDBCConnectionFactory() {

    super();
  }

  @Override
  public Connection getConnection() throws SQLException {

    Properties props = new Properties();

    if (stringHasValue(userId)) {
      props.setProperty("user", userId); //$NON-NLS-1$
    }

    if (stringHasValue(password)) {
      props.setProperty("password", password); //$NON-NLS-1$
    }
    props.setProperty("remarksReporting", remarksReporting);
    props.setProperty("useInformationSchema", useInformationSchema);
    props.setProperty("includeSynonyms", "true");

    props.putAll(otherProperties);

    Driver     driver = getDriver();
    Connection conn   = driver.connect(connectionURL, props);

    if (conn == null) {
      throw new SQLException(getString("RuntimeError.7")); //$NON-NLS-1$
    }

    return conn;
  }

  private Driver getDriver() {

    Driver driver;

    try {
      Class<?> clazz = ObjectFactory.externalClassForName(driverClass);
      driver = (Driver) clazz.getConstructor().newInstance();
    } catch (Exception e) {
      throw new RuntimeException(getString("RuntimeError.8"), e); //$NON-NLS-1$
    }

    return driver;
  }

  @Override
  public void addConfigurationProperties(Properties properties) {
    // this should only be called when this connection factory is
    // specified in a ConnectionFactory configuration
    userId               = properties.getProperty("userId"); //$NON-NLS-1$
    password             = properties.getProperty("password"); //$NON-NLS-1$
    connectionURL        = properties.getProperty("connectionURL"); //$NON-NLS-1$
    driverClass          = properties.getProperty("driverClass"); //$NON-NLS-1$
    remarksReporting     = properties.getProperty("remarksReporting", "true"); //$NON-NLS-1$
    useInformationSchema = properties.getProperty("remarksReporting", "true"); //$NON-NLS-1$

    otherProperties = new Properties();
    otherProperties.putAll(properties);

    // remove all the properties that we have specific attributes for
    otherProperties.remove("userId"); //$NON-NLS-1$
    otherProperties.remove("password"); //$NON-NLS-1$
    otherProperties.remove("connectionURL"); //$NON-NLS-1$
    otherProperties.remove("driverClass"); //$NON-NLS-1$
    otherProperties.remove("remarksReporting"); //$NON-NLS-1$
    otherProperties.remove("useInformationSchema"); //$NON-NLS-1$
  }

}
